import java.util.Arrays;
import java.util.Random;

public class Breeding {
	
	private static final double mutationRate = 0.5;
	private static final int genomeLength = 17;
	
	public static int[] doubleToBinary(double d){
		int[] binary = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};

		for(int i = genomeLength; i != 0; i--){
			if(binaryToDouble(binary) > d)
				binary[i] = 0;
			else
				binary[i] = 1;
			
			binary[i-1] = 1;
		}
		
		return binary;
		}
	
	public static double binaryToDouble(int[] binary){
		double d = 0;
		
		for(int i = 0; i < binary.length; i++){
			d += Math.pow(2, i)*binary[i];
		}
		d = d/(Math.pow(2, binary.length - 6)) - 32;
		
		return d;
	}
	
	public static int[] mutate(int[] binary){		
		for(int i = 0; i < binary.length; i++){
			if(Math.random() < mutationRate/(Math.pow(2, i/2)))
				binary[i] = 1 - binary[i];
		}
		
		return binary;
	}
	
	public static double splitBinary(int place, int[] parent, int[] child){
		for(int i = 0; i < parent.length; i++){
			if(i > place)
				child[i] = parent[i];
		}
		
		return binaryToDouble(child);
	}
	
	public static void newGeneration(MovementData[] bots){
		Random rand = new Random();
		int randomParent = 0;
		int place = 4;
		
		Arrays.sort(bots);
		
	      for(int i = 0; i < bots.length; i++){
	    	  System.out.println(bots[i].Fitness);
	      }
		
		for(int i = bots.length - 1; i > bots.length/2 - 1; i--){
			randomParent = rand.nextInt(bots.length/2);
			bots[i] = new MovementData(bots[randomParent]);
		}
		
		for(int i = bots.length - 1; i > 1 ; i--){
			if(i > bots.length/2 - 1)
				randomParent = rand.nextInt(bots.length/2);
			else
				randomParent = rand.nextInt(bots.length/2 + i - bots.length/2);
			
			bots[i].speedData.bearing = splitBinary(place, doubleToBinary(bots[randomParent].speedData.bearing), doubleToBinary(bots[i].speedData.bearing));
			bots[i].speedData.distanceToEnemy = splitBinary(place, doubleToBinary(bots[randomParent].speedData.distanceToEnemy), doubleToBinary(bots[i].speedData.distanceToEnemy));
			bots[i].speedData.headingEnemy = splitBinary(place, doubleToBinary(bots[randomParent].speedData.headingEnemy), doubleToBinary(bots[i].speedData.headingEnemy));
			bots[i].speedData.robotBackDistanceToWall = splitBinary(place, doubleToBinary(bots[randomParent].speedData.robotBackDistanceToWall), doubleToBinary(bots[i].speedData.robotBackDistanceToWall));
			bots[i].speedData.robotFrontDistanceToWall = splitBinary(place, doubleToBinary(bots[randomParent].speedData.robotFrontDistanceToWall), doubleToBinary(bots[i].speedData.robotFrontDistanceToWall));
			bots[i].speedData.robotLeftDistanceToWall = splitBinary(place, doubleToBinary(bots[randomParent].speedData.robotLeftDistanceToWall), doubleToBinary(bots[i].speedData.robotLeftDistanceToWall));
			bots[i].speedData.robotRightDistanceToWall = splitBinary(place, doubleToBinary(bots[randomParent].speedData.robotRightDistanceToWall), doubleToBinary(bots[i].speedData.robotRightDistanceToWall));
			bots[i].speedData.velocity = splitBinary(place, doubleToBinary(bots[randomParent].speedData.velocity), doubleToBinary(bots[i].speedData.velocity));
			
			bots[i].turnData.bearing = splitBinary(place, doubleToBinary(bots[randomParent].turnData.bearing), doubleToBinary(bots[i].turnData.bearing));
			bots[i].turnData.distanceToEnemy = splitBinary(place, doubleToBinary(bots[randomParent].turnData.distanceToEnemy), doubleToBinary(bots[i].turnData.distanceToEnemy));
			bots[i].turnData.headingEnemy = splitBinary(place, doubleToBinary(bots[randomParent].turnData.headingEnemy), doubleToBinary(bots[i].turnData.headingEnemy));
			bots[i].turnData.robotBackDistanceToWall = splitBinary(place, doubleToBinary(bots[randomParent].turnData.robotBackDistanceToWall), doubleToBinary(bots[i].turnData.robotBackDistanceToWall));
			bots[i].turnData.robotFrontDistanceToWall = splitBinary(place, doubleToBinary(bots[randomParent].turnData.robotFrontDistanceToWall), doubleToBinary(bots[i].turnData.robotFrontDistanceToWall));
			bots[i].turnData.robotLeftDistanceToWall = splitBinary(place, doubleToBinary(bots[randomParent].turnData.robotLeftDistanceToWall), doubleToBinary(bots[i].turnData.robotLeftDistanceToWall));
			bots[i].turnData.robotRightDistanceToWall = splitBinary(place, doubleToBinary(bots[randomParent].turnData.robotRightDistanceToWall), doubleToBinary(bots[i].turnData.robotRightDistanceToWall));
			bots[i].turnData.velocity = splitBinary(place, doubleToBinary(bots[randomParent].turnData.velocity), doubleToBinary(bots[i].turnData.velocity));
		}		
	}
}